package com.example.demo.controller;

import com.example.demo.Person;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.websocket.server.PathParam;
import java.io.File;
import java.util.Arrays;
import java.util.List;

@RequestMapping("/param") //开发中加上类路径，一是避免重复，二是方便查找代码
@RestController
public class ParamController {
    //使用Postman演示传递单个参数
    @RequestMapping("/m1")
    public String m1(String name) {
        return "接收到的参数name:" + name;
    }
    //底层逻辑：从请求的参数中，获取参数名为name的值，并给name赋值，参数名不能写错

    //使用Postman演示传递多个参数,此时，无所谓顺序
    @RequestMapping("/m2")
    public String m2(String name, Integer age) {
        return "接收到的参数name:" + name + ",age:" + age;
    }
    //与单个参数一样，也是直接传送，参数顺序无所谓

    //在开发时尽可能使用包装类型（Integer等），如果使用基本类型（int）必须要传值，否则会报错
    @RequestMapping("/m3")
    public String m3(String name, int age) {
        return "接收到的参数name:" + name + ",age:" + age;
    }

    //传递对象,此时直接传参就可以
    //开发中，接口的参数一般封装为对象，此时，如果增加或减少一个参数，不用改太多代码
    @RequestMapping("/m4")
    public String m4(Person person) {
        return "接收到的参数person:" + person.toString();
    }

    //后端参数重命名
    //可以使用@RequestParam("name")进行重命名，但是此时就变成了必传参数，不传参会报警告，且必须用@RequestParam声明里的名字
    //此时，需要加上required = false来修改， @RequestParam(value = "name", required = false)
    //可以把name看作前端参数，username看作后端参数
    @RequestMapping("/m5")
    public String m5(@RequestParam(value = "name", required = false) String username) {
        return "接收到的参数name:" + username;
    }

    //传递数组
    //当我们请求中，同一个参数有多个时，浏览器就会帮我们封装为一个数组
    //方法一（使用&符号进行连接）：http://127.0.0.1:8080/param/m6?arrayParam=zhangsan&arrayParam=wagnwu
    //方法二（使用,号）：http://127.0.0.1:8080/param/m6?arrayParam=zhangsan,lisi
    @RequestMapping("/m6")
    public String m6(String[] arrayParam) {
        return "接收到的参数arrayParam:" + Arrays.toString(arrayParam) + "长度：" + arrayParam.length;
    }

    //  传递集合
    //5开头通常属于服务器端发生错误
    //4开头通常属于客户端发生错误
    //传递集合时需要加上 @RequestParam 这个状态码
    //状态码分为Http状态码和业务状态码
    //Http状态码是系统返回的，不是后端定义的，2xx：成功，3xx：重定向，4xx：客户端错误，5xx：服务器端错误
    //业务状态码是在Http状态码响应成功下，业务的响应结果分为不同的状态，是后端自定义的
    @RequestMapping("/m7")
    public String m7(@RequestParam List<String> listParam) {
        return "接收到的参数arrayParam:" + listParam + "长度：" + listParam.size();
    }


    //前面几个的缺陷是扩展性差，当需求发生改变后就要修改接口的定义
    //这里的接口说的是API，指应用程序提供了哪些服务让调用方使用，接口对应到代码上通常指方法


    //  *最重要的是传递JSON,需要使用 @RequestBody 注解进行传递
    //JSON本质上是一个字符串，表示对象的字符串
    @RequestMapping("/m8")
    public String m8(@RequestBody Person person) {
        return "接收到的数据person:" + person.toString();
    }

    //获取URL中的参数
    //http://127.0.0.1:8080/param/m9/123，{}里的参数就会赋值为123，也可以使用这种方法获取多个参数
    //获取多个就在后面加/xx，例如：http://127.0.0.1:8080/param/m9/123/zhangsan，且顺序和数目都必须和定义的一样
    @RequestMapping("/m9/{userId}/{name}")
    public String m9(@PathVariable Integer userId, @PathVariable String name) {
        return "userId:" + userId + "  name:" + name;
    }

    //  传递文件
    @RequestMapping("/m10")
    public String m10(@RequestPart MultipartFile file) throws Exception{
        System.out.println(file.getOriginalFilename());
        file.transferTo(new File("D:/Junior/First Semester/Bit/ProtectFile/" + file.getOriginalFilename()));
        return "success!";
    }

    //  传递 Cookie & Session
    //cookie 和 session的区别
    //1.两者均是会话机制（会话：对话）
    //2.cookie是客户端机制，session是服务器端机制
    //3.cookie存在问题：可以伪造。session：分布式问题
    //分布式问题：对于服务而言，即使流量再小也会有至少两台机器，用来避免单点故障。
    // 假设只有两台机器，当用户发起请求时，此时请求到了A，A会创建一个session对象并保存。
    // 此时用户继续访问，请求列表，此时请求到了B，但是B并没有session，就不会为用户提供服务。
    // A和B不能同时存储这个用户的session
    // 解决方法：令牌方式（token解决），也可以让A和B进行网络通讯
    //4.session类似于 Map,可以存多个键值对
    //5.session 相当于学号，cookie 相当于学生证，session Id 存在 cookie 上
    //Http是无状态(记忆)的，现在请求和过一段时间请求，对于同样的参数，得到的结果是一样的(指处理逻辑一样，而不是数据一样)
    //Cookie 客户端机制
    //Session 服务器端机制
    //  使用Servlet获取 cookie 的两种方法
    @RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        //获取cookie的两种方式
        //for循环
        /*for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + ":" + cookie.getValue());
        }*/
        //lambda表达式
        if (cookies != null) {
            Arrays.stream(cookies).forEach(cookie -> {
                System.out.println(cookie.getName() + ":" + cookie.getValue());
            });
        }
        return "获取cookie成功！";
    }
    //  使用注解获取cookie
    //使用注解时，只能一个一个去拿 cookie
    @RequestMapping("/getCookie2")
    public String getCookie2(@CookieValue String bite, @CookieValue String aaa) {
        return "cookie中存取的值bite！" + bite + "  aaa：" + aaa;
    }
    //  获取Session
    //  先对 session 进行存储，获取到一个 session 的 id
    //cookie 和 session 之间的关联是通过 session 的 id 进行关联的
    @RequestMapping("/setSession")
    public String setSession(HttpServletRequest request) {
        HttpSession session = request.getSession();
        session.setAttribute("username", "zhangsan");
        return "success！";
    }
    //  使用Servlet获取 Session
    @RequestMapping("/getSession")
    public String getSession(HttpServletRequest request) {
        /*HttpSession session = request.getSession();*/
        HttpSession session = request.getSession(false);  //通过session的id获取session对象
        //这里参数默认为ture,如果没有session对象则会创建一个session,若参数为false，没有session就不会创建对象
        if (session != null) {
            String username = (String)session.getAttribute("username");
            return "登录用户：" + username;
        }
        return "session为空！";
    }
    //  使用注解获取 session，有两种方式
    //  1.使用@SessionAttribute获取
    //使用这种方式，@SessionAttribute默认是一个必传参数，需加 required = false
    @RequestMapping("/getSession2")
    public String getSession2(@SessionAttribute(required = false) String username) {
        return "username：" + username;
    }
    //  2.使用Spring内置对象
    @RequestMapping("/getSession3")
    public String getSession3(HttpSession session) {
        //参数 HttpSession session 等同于 getSession 的 HttpSession session = request.getSession(ture);
        String username = (String)session.getAttribute("username");
        return "登录用户：" + username;
    }

    //  获取Header,也是两种方式
    //  1.
    @RequestMapping("/getHeader")
    public String getHeader(HttpServletRequest request) {
        String userAgent = request.getHeader("user-Agent");
        return "userAgent：" + userAgent;
    }
    //  2.注解
    @RequestMapping("/getHeader2")
    public String getHeader2(@RequestHeader("user-Agent") String userAgent) {
        return "userAgent：" + userAgent;
    }


}
